home *** CD-ROM | disk | FTP | other *** search
- /*
- * rdbmp.c
- *
- * Copyright (C) 1994-1996, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- * For conditions of distribution and use, see the accompanying README file.
- *
- * This code contributed by James Arthur Boucher.
- * Modified by Peter Zingg, IMSI.
- * Exports a function, DIBtoJPEG, that converts a DIB (8, 16, or 24 bits per pixel) in
- * memory.
- */
-
- #define JPEG_INTERNALS
- #include "jinclude.h"
- #include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
-
- #ifdef BMP_SUPPORTED
-
- /* Macros to deal with unsigned chars as efficiently as compiler allows */
-
- #ifdef HAVE_UNSIGNED_CHAR
- typedef unsigned char U_CHAR;
- #define UCH(x) ((int) (x))
- #else /* !HAVE_UNSIGNED_CHAR */
- #ifdef CHAR_IS_UNSIGNED
- typedef char U_CHAR;
- #define UCH(x) ((int) (x))
- #else
- typedef char U_CHAR;
- #define UCH(x) ((int) (x) & 0xFF)
- #endif
- #endif /* HAVE_UNSIGNED_CHAR */
-
-
- /*
- typedef struct tagBITMAPINFOHEADER{ // bmih
- DWORD biSize;
- LONG biWidth;
- LONG biHeight;
- WORD biPlanes;
- WORD biBitCount
- DWORD biCompression;
- DWORD biSizeImage;
- LONG biXPelsPerMeter;
- LONG biYPelsPerMeter;
- DWORD biClrUsed;
- DWORD biClrImportant;
- } BITMAPINFOHEADER;
- */
-
- /* Private version of data source object */
-
- typedef struct _bmp_source_struct * bmp_source_ptr;
-
- typedef struct _bmp_source_struct {
- struct cjpeg_source_struct pub; /* public fields */
-
- j_compress_ptr cinfo; /* back link saves passing separate parm */
- HGLOBAL global_handle; /* Windows DIB handle */
- LPBYTE colormap; /* Start of colormap data */
- int colormap_entry_size; /* Colormap entry size (3 for RGBTRIPLE, 4 for RGBQUAD) */
- int colors; /* Number of colors in colormap */
- LPBYTE bitmap_data; /* Start of bitmap bits if handle is locked */
- JDIMENSION row_width; /* Physical width of scanlines in file */
- JDIMENSION source_row; /* Current source row number */
- } bmp_source_struct;
-
-
- LOCAL(int)
- bitmap_colors(LPBITMAPINFOHEADER lpbi)
- {
- int bits;
- LPBITMAPCOREHEADER lpbc = (LPBITMAPCOREHEADER)lpbi;
-
- /* With the BITMAPINFO format headers, the size of the palette
- * is in biClrUsed, whereas in the BITMAPCORE - style headers, it
- * is dependent on the bits per pixel ( = 2 raised to the power of
- * bits/pixel).
- */
- if (lpbi->biSize != sizeof(BITMAPCOREHEADER))
- {
- if (lpbi->biClrUsed != 0)
- return (int)lpbi->biClrUsed;
- bits = lpbi->biBitCount;
- }
- else
- {
- bits = lpbc->bcBitCount;
- }
-
- switch (bits)
- {
- case 1:
- return 2;
- case 4:
- return 16;
- case 8:
- return 256;
- default:
- break;
- }
- /* A 24 bitcount DIB has no color table */
- return 0;
- }
-
- LOCAL(int)
- bitmap_colormap_size(LPBITMAPINFOHEADER lpbi)
- {
- int colors = bitmap_colors(lpbi);
-
- if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
- return colors * sizeof(RGBTRIPLE);
- return colors * sizeof(RGBQUAD);
- }
-
- /*
- * Return the offset into the bitmap for the specified row.
- */
-
- LOCAL(JSAMPROW)
- get_bitmap_row_start(bmp_source_ptr source)
- {
- JDIMENSION offset = source->source_row * source->row_width;
- return (JSAMPROW)(source->bitmap_data + offset);
- }
-
- LOCAL(JSAMPROW)
- get_bitmap_color(bmp_source_ptr source, int color_index)
- {
- JDIMENSION offset = color_index * source->colormap_entry_size;
- return (JSAMPROW)(source->colormap + offset);
- }
-
- /*
- * Read one row of pixels.
- * The image has been read into the bitmap_data array, but is otherwise
- * unprocessed. We must read it out in top-to-bottom row order, and if
- * it is an 8-bit image, we must expand colormapped pixels to 24bit format.
- */
-
- METHODDEF(JDIMENSION)
- get_8bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
- /* This version is for reading 8-bit colormap indexes */
- {
- bmp_source_ptr source = (bmp_source_ptr) sinfo;
- register int color_index;
- register JSAMPROW color;
- register JSAMPROW inptr, outptr;
- register JDIMENSION col;
-
- /* Fetch next row from virtual array */
- source->source_row--;
-
- /* Expand the colormap indexes to real data */
- inptr = get_bitmap_row_start(source);
- outptr = source->pub.buffer[0];
- for (col = cinfo->image_width; col > 0; col--) {
- color_index = GETJSAMPLE(*inptr++);
- color = get_bitmap_color(source, color_index);
- *outptr++ = color[2]; /* can omit GETJSAMPLE() safely */
- *outptr++ = color[1];
- *outptr++ = color[0];
- }
-
- return 1;
- }
-
- #pragma pack(1)
- union color16 {
- struct {
- BYTE lo;
- BYTE hi;
- } w;
- struct {
- unsigned int r: 5;
- unsigned int g: 5;
- unsigned int b: 5;
- unsigned int d: 1;
- } rgb;
- };
- #pragma pack()
-
- METHODDEF(JDIMENSION)
- get_16bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
- /* This version is for reading 16-bit pixels */
- {
- bmp_source_ptr source = (bmp_source_ptr) sinfo;
- register JSAMPROW inptr, outptr;
- register JDIMENSION col;
- register union color16 color;
-
- /* Fetch next row from virtual array */
- source->source_row--;
-
- /* Transfer data. Note source values are in BGR order
- * (even though Microsoft's own documents say the opposite).
- */
- inptr = get_bitmap_row_start(source);
- outptr = source->pub.buffer[0];
- for (col = cinfo->image_width; col > 0; col--) {
- color.w.lo = GETJSAMPLE(*inptr++);
- color.w.hi = GETJSAMPLE(*inptr++);
- /* shift 5-bit RGB values to get them to 8 bit values */
- outptr[2] = color.rgb.r; /* can omit GETJSAMPLE() safely */
- if (outptr[2] == 0x1F)
- outptr[2] = 0xFF;
- else
- outptr[2] <<= 3;
- outptr[1] = color.rgb.g;
- if (outptr[1] == 0x1F)
- outptr[1] = 0xFF;
- else
- outptr[1] <<= 3;
- outptr[0] = color.rgb.b;
- if (outptr[0] == 0x1F)
- outptr[0] = 0xFF;
- else
- outptr[0] <<= 3;
- outptr += 3;
- }
-
- return 1;
- }
-
-
- METHODDEF(JDIMENSION)
- get_24bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
- /* This version is for reading 24-bit pixels */
- {
- bmp_source_ptr source = (bmp_source_ptr) sinfo;
- register JSAMPROW inptr, outptr;
- register JDIMENSION col;
-
- /* Fetch next row from virtual array */
- source->source_row--;
-
- /* Transfer data. Note source values are in BGR order
- * (even though Microsoft's own documents say the opposite).
- */
- inptr = get_bitmap_row_start(source);
- outptr = source->pub.buffer[0];
- for (col = cinfo->image_width; col > 0; col--) {
- outptr[2] = *inptr++; /* can omit GETJSAMPLE() safely */
- outptr[1] = *inptr++;
- outptr[0] = *inptr++;
- outptr += 3;
- }
-
- return 1;
- }
-
-
- /*
- * Extract information from bitmap header.
- * Set up parameters.
- * Set up buffers and get_pixel_row callback.
- */
-
- METHODDEF(void)
- start_input_bmp (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
- {
- int mapentrysize = 0;
- INT32 headerSize;
- INT32 biWidth = 0; /* initialize to avoid compiler warning */
- INT32 biHeight = 0;
- unsigned int biPlanes;
- int data_precision;
- int bits_per_pixel;
- int palette_colors;
- INT32 biCompression;
- INT32 biXPelsPerMeter,biYPelsPerMeter;
- JDIMENSION row_width;
- bmp_source_ptr source = (bmp_source_ptr) sinfo;
- LPBITMAPINFOHEADER lpbi = (LPBITMAPINFOHEADER)::GlobalLock(source->global_handle);
- LPBITMAPCOREHEADER lpbc;
-
- if (lpbi == NULL)
- ERREXIT(cinfo, JERR_BMP_NOT);
-
- palette_colors = bitmap_colors(lpbi);
- source->bitmap_data = (LPBYTE)lpbi + lpbi->biSize + bitmap_colormap_size(lpbi);
-
- /* The infoheader might be 12 bytes (OS/2 1.x), 40 bytes (Windows),
- * or 64 bytes (OS/2 2.x). Check the first 4 bytes to find out which.
- */
- headerSize = lpbi->biSize;
- if (headerSize < 12 || headerSize > 64)
- ERREXIT(cinfo, JERR_BMP_BADHEADER);
-
- switch ((int) headerSize) {
- case sizeof(BITMAPCOREHEADER):
- lpbc = (LPBITMAPCOREHEADER)lpbi;
- /* Decode OS/2 1.x header (Microsoft calls this a BITMAPCOREHEADER) */
- biWidth = lpbc->bcWidth;
- biHeight = lpbc->bcHeight;
- biPlanes = lpbc->bcPlanes;
- bits_per_pixel = lpbc->bcBitCount;
-
- switch (bits_per_pixel) {
- case 8: /* colormapped image */
- mapentrysize = 3; /* OS/2 uses RGBTRIPLE colormap */
- TRACEMS2(cinfo, 1, JTRC_BMP_OS2_MAPPED, (int) biWidth, (int) biHeight);
- break;
- case 16:
- case 24: /* RGB image */
- TRACEMS2(cinfo, 1, JTRC_BMP_OS2, (int) biWidth, (int) biHeight);
- break;
- default:
- ERREXIT(cinfo, JERR_BMP_BADDEPTH);
- break;
- }
- if (biPlanes != 1)
- ERREXIT(cinfo, JERR_BMP_BADPLANES);
- break;
- case 40:
- case 64:
- /* Decode Windows 3.x header (Microsoft calls this a BITMAPINFOHEADER) */
- /* or OS/2 2.x header, which has additional fields that we ignore */
- biWidth = lpbi->biWidth;
- biHeight = lpbi->biHeight;
- biPlanes = lpbi->biPlanes;
- bits_per_pixel = lpbi->biBitCount;
- biCompression = lpbi->biCompression;
- biXPelsPerMeter = lpbi->biXPelsPerMeter;
- biYPelsPerMeter = lpbi->biYPelsPerMeter;
- /* biSizeImage, biClrImportant fields are ignored */
-
- switch (bits_per_pixel) {
- case 8: /* colormapped image */
- mapentrysize = 4; /* RGBQUAD colormap */
- TRACEMS2(cinfo, 1, JTRC_BMP_MAPPED, (int) biWidth, (int) biHeight);
- break;
- case 16:
- case 24: /* RGB image */
- TRACEMS2(cinfo, 1, JTRC_BMP, (int) biWidth, (int) biHeight);
- break;
- default:
- ERREXIT(cinfo, JERR_BMP_BADDEPTH);
- break;
- }
- if (biPlanes != 1)
- ERREXIT(cinfo, JERR_BMP_BADPLANES);
- if (biCompression != 0)
- ERREXIT(cinfo, JERR_BMP_COMPRESSED);
-
- if (biXPelsPerMeter > 0 && biYPelsPerMeter > 0) {
- /* Set JFIF density parameters from the BMP data */
- cinfo->X_density = (UINT16) (biXPelsPerMeter/100); /* 100 cm per meter */
- cinfo->Y_density = (UINT16) (biYPelsPerMeter/100);
- cinfo->density_unit = 2; /* dots/cm */
- }
- break;
- default:
- ERREXIT(cinfo, JERR_BMP_BADHEADER);
- break;
- }
-
- /* Read the colormap, if any */
- if (mapentrysize > 0) {
- if (palette_colors <= 0)
- palette_colors = 256; /* assume it's 256 */
- else if (palette_colors > 256)
- ERREXIT(cinfo, JERR_BMP_BADCMAP);
-
- /* Point to colormap */
- source->colormap = (LPBYTE)lpbi + lpbi->biSize;
- source->colormap_entry_size = mapentrysize;
- source->colors = palette_colors;
- }
-
- /* Compute row width in file, including padding to 4-byte boundary */
- /* Set up to read from the virtual array in top-to-bottom order */
- switch (bits_per_pixel)
- {
- case 8:
- source->pub.get_pixel_rows = get_8bit_row;
- data_precision = 8;
- row_width = (JDIMENSION) biWidth; break;
- case 16:
- source->pub.get_pixel_rows = get_16bit_row;
- data_precision = 8;
- row_width = (JDIMENSION) (biWidth * 2); break;
- case 24:
- source->pub.get_pixel_rows = get_24bit_row;
- data_precision = 8;
- row_width = (JDIMENSION) (biWidth * 3); break;
- }
- while ((row_width & 3) != 0) row_width++;
-
- cinfo->in_color_space = JCS_RGB;
- cinfo->input_components = 3;
- cinfo->data_precision = data_precision;
- cinfo->image_width = (JDIMENSION) biWidth;
- cinfo->image_height = (JDIMENSION) biHeight;
-
- source->row_width = row_width;
- source->source_row = cinfo->image_height;
-
- /* Allocate one-row buffer for returned data */
- source->pub.buffer = (*cinfo->mem->alloc_sarray)
- ((j_common_ptr) cinfo, JPOOL_IMAGE,
- (JDIMENSION) (biWidth * 3), (JDIMENSION) 1);
- source->pub.buffer_height = 1;
- }
-
-
- /*
- * Finish up at the end of the file.
- */
-
- METHODDEF(void)
- finish_input_bmp (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
- {
- bmp_source_ptr source = (bmp_source_ptr) sinfo;
- if (source->bitmap_data == NULL)
- return;
-
- /* Done with global memory */
- ::GlobalUnlock(source->global_handle);
-
- /* Invalidate internal pointers */
- source->bitmap_data = NULL;
- source->colormap = NULL;
- }
-
-
- /*
- * The module selection routine for BMP format input.
- */
-
- GLOBAL(cjpeg_source_ptr)
- jinit_cvt_bmp (j_compress_ptr cinfo, HGLOBAL hDib)
- {
- bmp_source_ptr source;
-
- /* Create module interface object */
- source = (bmp_source_ptr)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
- SIZEOF(bmp_source_struct));
- source->cinfo = cinfo; /* make back link for subroutines */
- /* Fill in method ptrs, except get_pixel_rows which start_input sets */
- source->pub.start_input = start_input_bmp;
- source->pub.finish_input = finish_input_bmp;
- source->global_handle = hDib; /* Windows DIB handle */
- source->colormap = NULL;
- source->colormap_entry_size = 0;
- source->colors = 0;
- source->bitmap_data = NULL;
- source->source_row = 0; /* Current source row number */
- source->row_width = 0; /* Physical width of scanlines in file */
-
- return (cjpeg_source_ptr) source;
- }
-
-
- /*
- * The main program.
- */
-
- /* Create the add-on message string table. */
-
- #define JMESSAGE(code,string) string ,
-
- static const char * const cdjpeg_message_table[] = {
- #include "cderror.h"
- NULL
- };
-
-
- METHODDEF(void)
- save_output_message (j_common_ptr cinfo)
- {
- /* Create the message */
- char szErrorBuffer[JMSG_LENGTH_MAX];
- (*cinfo->err->format_message) (cinfo, szErrorBuffer);
- }
-
- class CMyException: public CException
- {
- DECLARE_DYNAMIC(CMyException)
-
- public:
- char m_szDesc[JMSG_LENGTH_MAX];
-
- // Implementation (use AfxThrowOleException to create)
- public:
- CMyException() { m_szDesc[0] = '\0'; }
- virtual BOOL GetErrorMessage(LPTSTR lpszError, UINT nMaxError, PUINT pnHelpContext = NULL)
- {
- if (m_szDesc[0] = '\0' || nMaxError <= 1)
- return FALSE;
-
- _tcsncpy(lpszError, m_szDesc, nMaxError-1);
- lpszError[nMaxError-1] = '\0';
- return TRUE;
- }
- };
-
- IMPLEMENT_DYNAMIC(CMyException, CException);
-
- METHODDEF(void)
- my_error_exit (j_common_ptr cinfo)
- {
- CMyException* pException = new CMyException;
-
- /* Always display the message. */
- /* We could postpone this until after returning, if we chose. */
- (*cinfo->err->format_message) (cinfo, pException->m_szDesc);
- THROW(pException);
- }
-
-
- JPEGLIB(int)
- DIBToJPEG (HGLOBAL hDib, LPCSTR outfilename)
- {
- int nError = -101;
- struct jpeg_compress_struct cinfo;
- struct jpeg_error_mgr jerr;
- #ifdef PROGRESS_REPORT
- struct cdjpeg_progress_mgr progress;
- #endif
- cjpeg_source_ptr src_mgr = NULL;
- FILE * output_file = NULL;
- JDIMENSION num_scanlines;
-
- const char* progname = "JpegLib"; /* in case C library doesn't provide it */
-
- /* Initialize the JPEG compression object with default error handling. */
- cinfo.err = jpeg_std_error(&jerr);
- jerr.output_message = save_output_message;
-
- jpeg_create_compress(&cinfo);
- /* Add some application-specific error messages (from cderror.h) */
- jerr.addon_message_table = cdjpeg_message_table;
- jerr.first_addon_message = JMSG_FIRSTADDONCODE;
- jerr.last_addon_message = JMSG_LASTADDONCODE;
-
- /* Now safe to enable signal catcher. */
- #ifdef NEED_SIGNAL_CATCHER
- enable_signal_catcher((j_common_ptr) &cinfo);
- #endif
-
- /* Initialize JPEG parameters.
- * Much of this may be overridden later.
- * In particular, we don't yet know the input file's color space,
- * but we need to provide some value for jpeg_set_defaults() to work.
- */
-
- cinfo.in_color_space = JCS_RGB; /* arbitrary guess */
- jpeg_set_defaults(&cinfo);
-
- /* Scan command line to find file names.
- * It is convenient to use just one switch-parsing routine, but the switch
- * values read here are ignored; we will rescan the switches after opening
- * the input file.
- */
-
- // file_index = parse_switches(&cinfo, argc, argv, 0, FALSE);
-
- /* Open the output file. */
- if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) {
- fprintf(stderr, "%s: can't open %s\n", progname, outfilename);
- // exit(EXIT_FAILURE);
- nError = -102;
- return nError;
- }
-
- TRY
- {
- #ifdef PROGRESS_REPORT
- start_progress_monitor((j_common_ptr) &cinfo, &progress);
- #endif
-
- /* Figure out the input file format, and set up to read it. */
-
-
- src_mgr = jinit_cvt_bmp(&cinfo, hDib);
- bmp_source_ptr source = (bmp_source_ptr) src_mgr;
- LPBITMAPINFOHEADER lpbi = (LPBITMAPINFOHEADER)::GlobalLock(source->global_handle);
- if (lpbi != NULL)
- {
- // do nothing if true color
- int bits_per_pixel = lpbi->biBitCount;
- if (bits_per_pixel > 24) // do nothing if true color
- {
- fclose(output_file);
- bool bSuc = DeleteFile(outfilename);
- nError = -102;
- return -555;
- }
- }
-
- /* Read the input file header to obtain file size & colorspace. */
- (*src_mgr->start_input) (&cinfo, src_mgr);
-
- /* Now that we know input colorspace, fix colorspace-dependent defaults */
- jpeg_default_colorspace(&cinfo);
-
- /* Adjust default compression parameters by re-parsing the options */
- // file_index = parse_switches(&cinfo, argc, argv, 0, TRUE);
-
- /* Specify data destination for compression */
- jpeg_stdio_dest(&cinfo, output_file);
-
- /* Start compressor */
- jpeg_start_compress(&cinfo, TRUE);
-
- /* Process data */
- while (cinfo.next_scanline < cinfo.image_height) {
- num_scanlines = (*src_mgr->get_pixel_rows) (&cinfo, src_mgr);
- (void) jpeg_write_scanlines(&cinfo, src_mgr->buffer, num_scanlines);
- }
- /* Finish compression and release memory */
- (*src_mgr->finish_input) (&cinfo, src_mgr);
- jpeg_finish_compress(&cinfo);
- jpeg_destroy_compress(&cinfo);
-
- /* Close files, if we opened them */
- fclose(output_file);
-
- #ifdef PROGRESS_REPORT
- end_progress_monitor((j_common_ptr) &cinfo);
- #endif
-
- nError = 0;
- }
- CATCH_ALL(e)
- {
- if (src_mgr != NULL)
- (*src_mgr->finish_input) (&cinfo, src_mgr);
-
- jpeg_destroy_compress(&cinfo);
-
- /* Close files, if we opened them */
- fclose(output_file);
- nError = -103;
- }
- END_CATCH_ALL
-
- /* All done. */
- // exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS);
- return nError;
- }
-
- #endif /* BMP_SUPPORTED */
-